package com.hspedu.seckill.service.impl;


import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hspedu.seckill.exception.GlobalException;
import com.hspedu.seckill.mapper.UserMapper;
import com.hspedu.seckill.pojo.User;
import com.hspedu.seckill.service.UserService;
import com.hspedu.seckill.util.CookieUtil;
import com.hspedu.seckill.util.MD5Util;
import com.hspedu.seckill.util.UUIDUtil;
import com.hspedu.seckill.util.ValidatorUtil;
import com.hspedu.seckill.vo.LoginVo;
import com.hspedu.seckill.vo.RespBean;
import com.hspedu.seckill.vo.RespBeanEnum;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author 兔兔鑫
 * @version 1.0
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    //依赖注入，注入 Spring 容器中的 bean
    @Resource
    private UserMapper userMapper;

    //配置RedisTemplate,操作Redis
    @Resource
    private RedisTemplate redisTemplate;

    /*
     * 登录功能
     */
    @Override
    public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {

        //接收到mobile(id)和password[midPass]（中间密码)
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();

        /*
         * 判断手机号（id） 和密码是否为空(14)
         * @NotNull注解代替
         */
//        if (!StringUtils.hasText(mobile) || !StringUtils.hasText(password)) {
//            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
//        }

        /*
         * 校验手机号码是否合格
         * @IsMobile注解代替
         */
//        if (!ValidatorUtil.isMobile(mobile)) {
//            return RespBean.error(RespBeanEnum.MOBILE_ERROR);
//        }

        //查询DB数据库, 看看用户是否存在
        /*
         * 自定义校验器 + 全局异常 ：复用性高
         */
        User user = userMapper.selectById(mobile);
        if (null == user) {//说明用户不存在
//            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
        //方法二：全局异常处理器处理
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }

        //如果用户存在，则比对密码!!
        //注意，我们从loginVo取出的密码是中间密码(即客户端经过一次加密加盐处理的密码)
        if (!MD5Util.midPassToDBPass(password, user.getSlat()).equals(user.getPassword())) {
            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
        }

        /*
         * 用户登录成功
         */
//        return RespBean.success();

        /*
         * 每个用户登录成功生成唯一的ticket，标识该用户的会话(29)。
         * 将用户信息与 ticket 关联，并存储在服务器的 session 中
         * 将 ticket 设置到用户的浏览器 cookie 中
         * 浏览器会在后续的请求中自动携带 ticket（通过 cookie）
         */
//        //给每个用户生成ticket-唯一
//        String ticket = UUIDUtil.uuid();
//        //将登录成功的用户user保存到session
//        request.getSession().setAttribute(ticket, user);
//        //将ticket保存到cookie
//        CookieUtil.setCookie(request, response, "userTicket", ticket);
//        //这里我们需要返回userTicket
//        return RespBean.success(ticket);

        /*
         * 为了实现分布式Session, 把登录的用户信息非原生存放到Redis(44)
         */
        //给每个用户生成ticket-唯一
        String ticket = UUIDUtil.uuid();
        //redisTemplate做了序列化处理
        System.out.println("使用的 redisTemplate->" + redisTemplate.hashCode());
        //redis存储session的样式   key: "user:" + ticket , value: user的信息
        redisTemplate.opsForValue().set("user:" + ticket, user);
        //将ticket保存到cookie
        CookieUtil.setCookie(request, response, "userTicket", ticket);
        //这里我们需要返回userTicket(94)
//        return RespBean.success();
        return RespBean.success(ticket);
    }

    //根据Cookie-ticket 在redis获取用户信息(45)
    @Override
    public User getUserByCookie(String userTicket, HttpServletRequest request, HttpServletResponse response) {

        if (!StringUtils.hasText(userTicket)) {
            return null;
        }

        //根据userTicket到Redis获取user
        User user = (User) redisTemplate.opsForValue().get("user:" + userTicket);
        //如果用户不为null, 就重新设置cookie, 相当于刷新, 这里是根据你的业务需要来的。cookie有一定生命周期可能会过期。
        //Cookie通常有一个过期时间。如果用户在一定时间内没有活动，Cookie会过期，用户会被强制登出。通过在每次用户请求时刷新Cookie
        if (user != null) {
            CookieUtil.setCookie(request, response, "userTicket", userTicket);
        }

        return user;
    }

    //更新用户密码(108)
    @Override
    public RespBean updatePassword(String userTicket,
                                   String password,
                                   HttpServletRequest request,
                                   HttpServletResponse response) {
        //通过userTicket从redis拿到user
        User user = getUserByCookie(userTicket, request, response);
        if (user == null) {
            //抛出异常
            throw new GlobalException(RespBeanEnum.MOBILE_NOT_EXIST);
        }
        //设置新密码
        user.setPassword(MD5Util.inputPassToDBPass(password, user.getSlat()));
        int i = userMapper.updateById(user);
        if (i == 1) { //更新成功
            //删除该用户在Redis数据
            redisTemplate.delete("user:" + userTicket);
            return RespBean.success();
        }
        return RespBean.error(RespBeanEnum.PASSWORD_UPDATE_FAIL);
    }
}
